1 /* 2 * The MIT License (MIT) 3 * 4 * Copyright (c) 2014 Devisualization (Richard Andrew Cattermole) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 module devisualization.window.interfaces.eventable; 25 import std..string : toUpper; 26 import std.algorithm : filter, moveAll; 27 28 /** 29 * Provides an interface version of an eventing mechanism. 30 * 31 * See_Also: 32 * Eventing 33 */ 34 mixin template IEventing(string name, T...) { 35 mixin("void add" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(bool delegate(T));}); 36 mixin("void add" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(void delegate(T));}); 37 38 mixin("void remove" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(bool delegate(T));}); 39 mixin("void remove" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(void delegate(T));}); 40 41 mixin("size_t count" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ "();"); 42 43 mixin("void clear" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{();}); 44 45 static if (__traits(compiles, typeof(this)) && is(typeof(this) : T[0])) { 46 mixin("void " ~ name ~ q{(T[1 .. $] args);}); 47 } else { 48 mixin("void " ~ name ~ q{(T args);}); 49 } 50 } 51 52 53 /** 54 * Implements an eventable interface for something. 55 * Includes support for bool delegate(T) and void delegate(T). 56 * Will consume a call to all delegates if it returns true. Default false. 57 * 58 * Example usage: 59 * mixin Eventing!("onNewListing", ListableObject); 60 * 61 * If is(T[0] == typeof(this)) then it'll use this as being the first argument. 62 */ 63 mixin template Eventing(string name, T...) { 64 private { 65 mixin(q{bool delegate(T)[] } ~ name ~ "_;"); 66 mixin(q{bool delegate(T)[size_t] } ~ name ~ "_assoc;"); 67 68 union ptrToSizeT { 69 void delegate(T) from; 70 size_t value; 71 } 72 } 73 74 mixin("void add" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(void delegate(T) value) { 75 mixin(name ~ "_ ~= (T args) => {value(args); return false;}();"); 76 mixin(name ~ "_assoc[ptrToSizeT(value).value] = " ~ name ~ "_[$-1];"); 77 }}); 78 79 mixin("void add" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(bool delegate(T) value) { 80 mixin(name ~ "_ ~= value;"); 81 }}); 82 83 mixin("void remove" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(bool delegate(T) value) { 84 import std.range : walkLength; 85 86 mixin("auto t = filter!(a => a !is value)(" ~ name ~ "_);"); 87 t.moveAll(mixin(name ~ "_")); 88 mixin(name ~ "_.length = t.walkLength;"); 89 }}); 90 91 mixin("void remove" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(void delegate(T) value) { 92 if (ptrToSizeT(value).value in mixin(name ~ "_assoc")) { 93 mixin("remove" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ "(" ~ name ~ "_assoc[ptrToSizeT(value).value]);"); 94 mixin(name ~ "_assoc.remove(ptrToSizeT(value).value);"); 95 } 96 }}); 97 98 mixin("size_t count" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{(){ 99 return cast(size_t)(mixin(name ~ "_.length") + mixin(name ~ "_assoc.length")); 100 }}); 101 102 mixin("void clear" ~ toUpper(name[0] ~ "") ~ name[1 ..$] ~ q{() { 103 mixin(name ~ "_") = []; 104 }}); 105 106 static if (__traits(compiles, typeof(this)) && is(typeof(this) : T[0])) { 107 mixin("void " ~ name ~ q{(T[1 .. $] args) { 108 foreach (del; mixin(name ~ "_")) { 109 if (del(this, args)) 110 return; 111 } 112 }}); 113 } else { 114 mixin("void " ~ name ~ q{(T args) { 115 foreach (del; mixin(name ~ "_")) { 116 if (del(args)) 117 return; 118 } 119 }}); 120 } 121 }